package com.tanjie.blackbean.core.util;

import cn.hutool.core.bean.BeanUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.tanjie.blackbean.pojo.auth.UserInfo;
import com.tanjie.blackbean.pojo.auth.UserInfoWithRolesAndPerms;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.tanjie.blackbean.pojo.auth.AuthConst.*;

/**
 * @author: tanjie
 * @date: 2021-11-08
 **/
@Slf4j
public abstract class TokenUtil {

    private TokenUtil() {
    }

    public static Algorithm alg = Algorithm.HMAC256(DEFAULT_TOKEN_SECRET);

    public static String createToken(Map<String, ?> payloadClaims, Date expTime) throws Exception {
        return JWT.create()
                .withIssuer("blackbean")
                .withExpiresAt(expTime)
                .withPayload(payloadClaims)
                .withIssuedAt(new Date())
                .sign(alg);
    }

    public static String createToken(UserInfoWithRolesAndPerms userInfo, Date expTime) throws Exception {
        Map<String, Object> map = BeanUtil.beanToMap(BeanUtil.copyProperties(userInfo, UserInfo.class));
        map.put("userType", userInfo.getUserType().name());
        map.put("clientType", userInfo.getClientType().name());
        return TokenUtil.createToken(map, expTime);
    }

    public static String createRefreshToken(String userId) throws Exception {
        Map<String, String> param = new HashMap<>(16);
        param.put(TOKEN_TYPE, REFRESH_TOKEN);
        param.put(USER_ID, userId);
        return JWT.create()
                .withIssuer("")
                .withPayload(param)
                .withIssuedAt(new Date())
                .sign(alg);
    }

    public static Map<String, Claim> parseToken(String token) {
        try {
            JWTVerifier verifier = JWT.require(alg).build();
            DecodedJWT decodedJWT = verifier.verify(token);
            return decodedJWT.getClaims();
        } catch (JWTDecodeException e) {
            log.error("解析token失败，cause：{}", e.getMessage());
            return null;
        }
    }

    public static UserInfo parseUserInfo(String token) throws Exception {
        JWTVerifier verifier = JWT.require(alg).build();
        DecodedJWT decodedJWT = verifier.verify(token);
        Map<String, Claim> map = decodedJWT.getClaims();
        Map<String, Object> transferMap = new HashMap<>(16);
        for (String key : map.keySet()) {
            Claim claim = map.get(key);
            Object o = claim.as(Object.class);
            transferMap.put(key, o);
        }
        return BeanUtil.toBean(transferMap, UserInfo.class);
    }

    public static boolean verifyToken(String token) {
        try {
            JWTVerifier verifier = JWT.require(alg)
                    .withIssuer("")
                    .acceptExpiresAt(0)
                    .build();
            verifier.verify(token);
        } catch (JWTVerificationException e) {
            log.error("token校验失败，cause: {}", e.getMessage());
            return false;
        }
        return true;
    }

}
